////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copyright (c) 2009 - 2010 RacoonStudios
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy of this
/// software and associated documentation files (the "Software"), to deal in the Software
/// without restriction, including without limitation the rights to use, copy, modify, merge,
/// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
/// to whom the Software is furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all copies or
/// substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
/// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
/// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
/// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
/// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/// DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once
#ifndef factory_h__
#define factory_h__

#include "helper/array.h"
#include "helper/string.h"
#include "helper/fcc.h"
#include "helper/dictionary.h"
#include "helper/hashtable.h"
#include "core/smartptr.h"

namespace Core
{

	class ReferenceCount;
	class Rtti;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \class	Factory
	///
	/// \brief	Every class which inherits from the RefCounter class will register
	///			itself to this class so that we can have a look over their existence.
	///
	///	\todo	Ad documentation! 
	///
	/// \author	khaos
	/// \date	05.01.2010
	////////////////////////////////////////////////////////////////////////////////////////////////////
	class Factory
	{
	public:

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	public: static Factory * Instance()
		///
		/// \brief	Creates the Factory.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \return	A pointer.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static Factory * Instance();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static void Destroy()
		///
		/// \brief	Destroys the Factory.
		///
		/// \author	khaos
		/// \date	05.01.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static void Destroy();




		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void Register(const Rtti * rtti, const Helper::String & name, const Helper::FCC & fcc)
		///
		/// \brief	This procedure registeres a Rtti object and by this a class inherites from
		///			RefCounter with the Factory.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \param	[in]	rtti	The rtti of the class we want to add. 
		/// \param	[in]	name	The name of the class we want to add. 
		/// \param	[in]	fcc		The fcc of the class we want to add. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void Register(const Rtti * rtti, const Helper::String & name, const Helper::FCC & fcc);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool ClassExists(const Helper::String & name) const
		///
		/// \brief	Determines if the through its name specified class exists.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \param	[in]	name	The name of the class. 
		///
		/// \return	True if the class exists, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool ClassExists(const Helper::String & name) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool ClassExists(const Helper::FCC fcc) const
		///
		/// \brief	Determines if the through its FCC specified class exists.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \param	[in]	fcc	The fcc of the class. 
		///
		/// \return	True if the class exists, otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool ClassExists(const Helper::FCC fcc) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	const Rtti * GetClassRtti(const Helper::String & name) const
		///
		/// \brief	Returns the Rtti pointer of the through its name specified class.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \param	[in]	name	The name of the class. 
		///
		/// \return	Pointer to the Rtti of the specified class if it exists,
		///			otherwise NULL.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		const Rtti * GetClassRtti(const Helper::String & name) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	const Rtti * GetClassRtti(const Helper::FCC & fcc) const
		///
		/// \brief	Returns the Rtti pointer of the through its FCC specified class.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \param	[in]	fcc	The fcc of the class. 
		///
		/// \return	Pointer to the Rtti of the specified class if it exists,
		///			otherwise false.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		const Rtti * GetClassRtti(const Helper::FCC & fcc) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	ReferenceCount * Create(const Helper::String & name) const
		///
		/// \brief	Creates the through its name specified class.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \param	name	The name of the class. 
		///
		/// \return	A pointer to this instance.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		ReferenceCount * Create(const Helper::String & name) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	ReferenceCount * Create(const Helper::FCC fcc) const
		///
		/// \brief	Creates the through its FCC specified class.
		///
		/// \author	khaos
		/// \date	05.01.2010
		///
		/// \param	fcc	The fcc of the class. 
		///
		/// \return	A pointer to this instance.
		////////////////////////////////////////////////////////////////////////////////////////////////////
		ReferenceCount * Create(const Helper::FCC fcc) const;

	protected:

	private:

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn Factory()
		///
		/// \brief	Constructor.
		///
		/// \author	khaos
		/// \date	05.01.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		Factory();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	virtual ~Factory()
		///
		/// \brief	Finaliser. 
		///
		/// \author	khaos
		/// \date	05.01.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual ~Factory();



		static Factory * Singleton;

		Helper::HashTable<Helper::String, const Rtti*> m_names;
		Helper::Dictionary<Helper::FCC, const Rtti*> m_fccs;

	};

}

#endif // factory_h__